package org.dizena.common.logger;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.core.spi.ScanException;
import jakarta.annotation.Resource;
import org.dizena.common.base.cons.ConstantKey;
import org.dizena.common.logger.appender.LogRollingFileAppender;
import org.dizena.common.logger.bean.LogLocEvent;
import org.dizena.common.logger.bean.LogRpcEvent;
import org.dizena.common.utils.LogUtil;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

@Order(1)
@Configuration
@EnableConfigurationProperties(LogbackProperties.class)
@ConditionalOnProperty(
        prefix = "common.logger",
        value = {"enabled"},
        havingValue = "true"
)
public class LogbackAutoConfig implements CommandLineRunner {
    @Bean("logExecutor")
    public Executor logExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(Runtime.getRuntime().availableProcessors());
        executor.setMaxPoolSize(executor.getCorePoolSize() * 2);
        executor.setQueueCapacity(200);
        executor.setKeepAliveSeconds(60);
        executor.setThreadNamePrefix("thread-pool-log-");
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setAwaitTerminationSeconds(60);
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }

    @Async("logExecutor")
    @EventListener
    public void handleLocEvent(LogLocEvent e) {
        LogUtil.outLog(e.getLogger(), e.getLevelEnum(), e.getLogInfo());
    }

    @Async("logExecutor")
    @EventListener
    public void handleRpcEvent(LogRpcEvent e) {
        LogUtil.outLog(e.getLogger(), e.getLevelEnum(), e.getLogInfo());
    }

    @Resource
    private LogbackProperties properties;
    private LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
    org.slf4j.Logger logger = LoggerFactory.getLogger(LogbackAutoConfig.class);

    private Logger createLogger(String loggerName) throws ScanException {
        Logger logger = loggerContext.getLogger(loggerName);
        String basePath;
        if (org.slf4j.Logger.ROOT_LOGGER_NAME.equals(loggerName)) {
            basePath = properties.getPath();
        } else {
            basePath = properties.getPath() + "/" + loggerName;
        }
        logger.info("log file path {}", basePath);
        logger.addAppender(new LogRollingFileAppender(loggerContext, properties).getRollingFileAppender(basePath, Level.ERROR));
        logger.addAppender(new LogRollingFileAppender(loggerContext, properties).getRollingFileAppender(basePath, Level.WARN));
        logger.addAppender(new LogRollingFileAppender(loggerContext, properties).getRollingFileAppender(basePath, Level.INFO));
        logger.addAppender(new LogRollingFileAppender(loggerContext, properties).getRollingFileAppender(basePath, Level.DEBUG));
        logger.addAppender(new LogRollingFileAppender(loggerContext, properties).getRollingFileAppender(basePath, Level.TRACE));
        if (!org.slf4j.Logger.ROOT_LOGGER_NAME.equals(loggerName)) {
            logger.setAdditive(false);
        }
        return logger;
    }

    @Override
    public void run(String... args) throws Exception {
        //rpc
        createLogger(ConstantKey.RPC_LOG_DIR);

        createLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);

        //end
        logger.info("【自动化配置】---Logger Custom 配置初始化");
    }

}
